redis 集群模式接入使用

第三方组件声明

因依赖于第三方版本,请第三方组件、中间件和本文保持一致,避免由于第三方升级的兼容性导致无法正常使用。

启动 Redis 集群

使用 Docker 一键启动 Redis 集群(6 节点:3 主 3 从):

docker run --name redis-cluster -d \
  -e CLUSTER_ANNOUNCE_IP=192.168.0.31 \
  -p 7000-7005:7000-7005 \
  -p 17000-17005:17000-17005 \
  registry.cn-hangzhou.aliyuncs.com/dockerhub_mirror/redis-cluster:4.0
IP 地址配置

请将 CLUSTER_ANNOUNCE_IP 参数修改为实际的宿主机 IP 地址,确保集群节点间能够正常通信。

客户端连接测试

使用 redis-cli 连接集群并查看节点状态:

./redis-cli -c -h 192.168.0.31 -p 7000

# 查看集群节点信息
192.168.0.31:7000> cluster nodes
集群状态

成功执行 cluster nodes 命令后,可看到 6 个节点信息,包括 3 个 master 节点和 3 个 slave 节点,以及各自负责的 slot 范围。

PIGX 应用配置

修改 Nacos 配置

编辑 nacos 配置中心的 application-dev.yml 文件:

spring:
  data:
    redis:
      cluster:
        enable: true
        nodes:
          - pigx-redis:7000
          - pigx-redis:7001
          - pigx-redis:7002
          - pigx-redis:7003
          - pigx-redis:7004
          - pigx-redis:7005
配置说明
  • cluster.enable: true 启用集群模式
  • nodes 配置所有集群节点地址(Docker 环境使用容器名,生产环境使用实际 IP)

重启应用

修改配置后,重启 PIGX 应用使配置生效。

扩展说明

集群高可用问题

版本说明

针对 PIGX 3.4 及以下版本,3.5+ 版本已默认支持集群高可用。

在 Redis Cluster 模式下,停用任何一个 master 或 slave 节点可能导致应用无法登录。相关问题见:Issue #664

问题原因

Spring Boot 2.x 默认使用 lettuce 作为 Redis 连接客户端,但自适应拓扑刷新(Adaptive updates)与定时拓扑刷新(Periodic updates)默认关闭。这导致 Redis Cluster 或 Sentinel 的拓扑变化不会通知到 lettuce 连接。

参考文档:Refreshing the cluster topology view

解决方案一:启用拓扑刷新

RedisTemplateConfigDynamicRouteAutoConfiguration 中添加以下 Bean:

@Bean
@ConditionalOnProperty(value = "spring.redis.cluster.nodes", matchIfMissing = true)
public LettuceConnectionFactory redisConnectionFactory(RedisProperties redisProperties) {
  RedisClusterConfiguration redisClusterConfiguration =
    new RedisClusterConfiguration(redisProperties.getCluster().getNodes());

  // 启用拓扑刷新
  ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
    .enablePeriodicRefresh()
    .enableAllAdaptiveRefreshTriggers()
    .refreshPeriod(Duration.ofSeconds(5))
    .build();

  ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()
    .topologyRefreshOptions(clusterTopologyRefreshOptions)
    .build();

  // 配置读写分离
  LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder()
    .readFrom(ReadFrom.SLAVE_PREFERRED)
    .clientOptions(clusterClientOptions)
    .build();

  return new LettuceConnectionFactory(redisClusterConfiguration, lettuceClientConfiguration);
}
配置说明
  • enablePeriodicRefresh() 启用定时刷新拓扑
  • refreshPeriod(Duration.ofSeconds(5)) 每 5 秒刷新一次(不要设置过小)
  • ReadFrom.SLAVE_PREFERRED 优先从从节点读取,实现读写分离

RedisTemplateConfig 微调

RedisTemplateConfig 配置

解决方案二:使用 Jedis

更简单的解决方案是使用 jedis 替代 lettuce

在所有使用 spring-boot-starter-data-redis 的模块中排除 lettuce 依赖:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
  <exclusions>
    <exclusion>
      <groupId>io.lettuce</groupId>
      <artifactId>lettuce-core</artifactId>
    </exclusion>
  </exclusions>
</dependency>

<!-- 添加 Jedis 依赖 -->
<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
</dependency>
排除 lettuce 依赖
方案选择
  • 方案一:适合需要高级功能(如异步操作、响应式编程)的场景
  • 方案二:更简单直接,适合常规使用场景